package middleware

import (
	"database/sql"
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"runtime"
	"runtime/debug"
	"xinduobang/stock/common"
	"xinduobang/stock/common/fisherrors"
	"xinduobang/stock/utils"
)

func ErrorHandler() gin.HandlerFunc {
	return func(c *gin.Context) {
		defer func() {
			// 通过recover获取错误信息
			if r := recover(); r != nil {
				//log.Error("✅✅1✅✅")
				fishAndNomalErrHandler(c, r.(error))
				c.Abort()
			}
		}()
		c.Next()
		//log.Error("✅✅2✅✅")
		for _, e := range c.Errors {
			//log.Error("✅✅3✅✅")
			ginErrorHandler(c, e)
			return
		}
	}
}

func getStackTrace() string {
	buf := make([]byte, 1<<16)
	stackSize := runtime.Stack(buf, false)
	return string(buf[:stackSize])
}

func printStackTrace(c *gin.Context) {
	// 获取栈信息
	buf := make([]byte, 1<<16)
	stackSize := runtime.Stack(buf, false)

	// 获取源代码行号
	pc := make([]uintptr, 32)
	n := runtime.Callers(1, pc) // 跳过前3个调用，其中包括printStackTrace()和recover()
	frames := runtime.CallersFrames(pc[:n])

	// 打印栈信息和源代码行号
	utils.Error(c, "Stack Trace:")
	for {
		frame, more := frames.Next()
		utils.Errorf(c, "%s:%d\n", frame.File, frame.Line)
		if !more {
			break
		}
	}
	utils.Error(c, string(buf[:stackSize]))
}

func fishAndNomalErrHandler(c *gin.Context, e error) {
	if e == nil {
		return
	}

	data := map[string]string{}
	cfg := common.GetConfig()

	if fishErr, ok := e.(*fisherrors.FishError); ok {
		utils.Error(c, fishErr.ToString())
		if cfg.Server.Debug {
			if fishErr.Err != nil {
				// data["err_msg"] = fishErr.Err.Error()
			}
		}
		c.AbortWithStatusJSON(http.StatusOK, gin.H{
			"code": fishErr.Code,
			"msg":  fishErr.Msg,
			"data": data,
		})
	} else {
		if cfg.Server.Debug {
			data["err_msg"] = e.Error()
		}
		if e == sql.ErrNoRows {
			utils.Error(c, fmt.Sprintf("error: %v ", e.Error()), e)
			c.AbortWithStatusJSON(http.StatusOK, gin.H{
				"code": fisherrors.CodeDataQueryError,
				"msg":  "查询数据错误",
				"data": data,
			})
		} else {
			utils.Error(c, "❌ ❌ ❌ 系统 panic: error:"+e.Error()+string(debug.Stack()))

			c.AbortWithStatusJSON(http.StatusOK, gin.H{
				"code": http.StatusInternalServerError,
				"msg":  "服务器异常",
				"data": data,
			})
		}
	}
}

func ginErrorHandler(c *gin.Context, e *gin.Error) {
	if e.Err == nil {
		return
	}

	if fishErr, ok := e.Err.(*fisherrors.FishError); ok {
		utils.Error(c, fishErr.ToString())
		//log.Error(fmt.Sprintf("fish_error: %v fish_error_code:%v fish_error_data:%v origin_err_msg:%v", fishErr.Msg, fishErr.Code, fishErr.Data, fishErr.Err))
	} else {
		utils.Error(c, fmt.Sprintf("error: %+v ", e))
	}
}
